#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, unused_attributes, non_camel_case_types)]
#![allow(clippy::derive_partial_eq_without_eq, clippy::disallowed_names)]

use async_trait::async_trait;
use futures::Stream;
#[cfg(feature = "mock")]
use mockall::automock;
use std::error::Error;
use std::collections::BTreeSet;
use std::task::{Poll, Context};
use swagger::{ApiError, ContextWrapper, auth::Authorization};
use serde::{Serialize, Deserialize};

#[cfg(any(feature = "client", feature = "server"))]
type ServiceError = Box<dyn Error + Send + Sync + 'static>;

pub const BASE_PATH: &str = "{{{basePathWithoutHost}}}";
{{#appVersion}}
pub const API_VERSION: &str = "{{{.}}}";
{{/appVersion}}

mod auth;
pub use auth::{AuthenticationApi, Claims};


{{#apiInfo}}
  {{#apis}}
    {{#operations}}
      {{#operation}}
{{>response}}

      {{/operation}}
    {{/operations}}
  {{/apis}}
{{/apiInfo}}
/// API
#[cfg_attr(feature = "mock", automock)]
#[async_trait]
#[allow(clippy::too_many_arguments, clippy::ptr_arg)]
pub trait Api<C: Send + Sync> {
{{#apiInfo}}
  {{#apis}}
    {{#operations}}
      {{#operation}}
{{#summary}}
    /// {{{.}}}
{{/summary}}
    async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}(
        &self,
{{#allParams}}
        {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{/isArray}}{{{dataType}}}{{^required}}>{{/required}},
{{/allParams}}
        context: &C) -> Result<{{{operationId}}}Response, ApiError>;

      {{/operation}}
    {{/operations}}
  {{/apis}}
{{/apiInfo}}
}

/// API where `Context` isn't passed on every API call
#[cfg_attr(feature = "mock", automock)]
#[async_trait]
#[allow(clippy::too_many_arguments, clippy::ptr_arg)]
pub trait ApiNoContext<C: Send + Sync> {
    // The std::task::Context struct houses a reference to std::task::Waker with the lifetime <'a>.
    // Adding an anonymous lifetime `'a` to allow mockall to create a mock object with the right lifetimes.
    // This is needed because the compiler is unable to determine the lifetimes on F's trait bound
    // where F is the closure created by mockall. We use higher-rank trait bounds here to get around this.

    fn context(&self) -> &C;

{{#apiInfo}}
  {{#apis}}
    {{#operations}}
      {{#operation}}
{{#summary}}
    /// {{{.}}}
{{/summary}}
    async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}(
        &self,
{{#allParams}}
        {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{{dataType}}}{{^required}}>{{/required}},
{{/allParams}}
        ) -> Result<{{{operationId}}}Response, ApiError>;

      {{/operation}}
    {{/operations}}
  {{/apis}}
{{/apiInfo}}
}

/// Trait to extend an API to make it easy to bind it to a context.
pub trait ContextWrapperExt<C: Send + Sync> where Self: Sized
{
    /// Binds this API to a context.
    fn with_context(self, context: C) -> ContextWrapper<Self, C>;
}

impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt<C> for T {
    fn with_context(self: T, context: C) -> ContextWrapper<T, C> {
         ContextWrapper::<T, C>::new(self, context)
    }
}

#[async_trait]
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ApiNoContext<C> for ContextWrapper<T, C> {
    fn context(&self) -> &C {
        ContextWrapper::context(self)
    }

{{#apiInfo}}
  {{#apis}}
    {{#operations}}
      {{#operation}}
{{#summary}}
    /// {{{.}}}
{{/summary}}
    async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}(
        &self,
{{#allParams}}
        {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{{dataType}}}{{^required}}>{{/required}},
{{/allParams}}
        ) -> Result<{{{operationId}}}Response, ApiError>
    {
        let context = self.context().clone();
        self.api().{{#exts}}{{{x-operation-id}}}{{/exts}}({{#allParams}}{{{paramName}}}, {{/allParams}}&context).await
    }

      {{/operation}}
    {{/operations}}
  {{/apis}}
{{/apiInfo}}
}

{{#hasCallbacks}}

{{#apiInfo}}
    {{#apis}}
      {{#operations}}
        {{#operation}}
          {{#callbacks}}
            {{#urls}}
              {{#requests}}
{{>response}}

            {{/requests}}
          {{/urls}}
        {{/callbacks}}
      {{/operation}}
    {{/operations}}
  {{/apis}}
{{/apiInfo}}

/// Callback API
#[cfg_attr(feature = "mock", automock)]
#[async_trait]
pub trait CallbackApi<C: Send + Sync> {

{{#apiInfo}}
  {{#apis}}
    {{#operations}}
      {{#operation}}
        {{#callbacks}}
          {{#urls}}
            {{#requests}}
{{#summary}}
    /// {{{.}}}
{{/summary}}
    async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}(
        &self,
{{#exts}}
  {{#x-callback-params}}
        callback_{{.}}: String,
  {{/x-callback-params}}
{{/exts}}
{{#allParams}}
        {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{{dataType}}}{{^required}}>{{/required}},
{{/allParams}}
        context: &C) -> Result<{{{operationId}}}Response, ApiError>;

            {{/requests}}
          {{/urls}}
        {{/callbacks}}
      {{/operation}}
    {{/operations}}
  {{/apis}}
{{/apiInfo}}
}

/// Callback API without a `Context`
#[cfg_attr(feature = "mock", automock)]
#[async_trait]
pub trait CallbackApiNoContext<C: Send + Sync> {

    fn context(&self) -> &C;

{{#apiInfo}}
  {{#apis}}
    {{#operations}}
      {{#operation}}
        {{#callbacks}}
          {{#urls}}
            {{#requests}}
{{#summary}}
    /// {{{.}}}
{{/summary}}
    async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}(
        &self,
{{#exts}}
  {{#x-callback-params}}
        callback_{{.}}: String,
  {{/x-callback-params}}
{{/exts}}
{{#allParams}}
        {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{{dataType}}}{{^required}}>{{/required}},
{{/allParams}}
        ) -> Result<{{{operationId}}}Response, ApiError>;

            {{/requests}}
          {{/urls}}
        {{/callbacks}}
      {{/operation}}
    {{/operations}}
  {{/apis}}
{{/apiInfo}}
}

pub trait CallbackContextWrapperExt<C: Send + Sync> where Self: Sized
{
    /// Binds this API to a context.
    fn with_context(self, context: C) -> ContextWrapper<Self, C>;
}

impl<T: CallbackApi<C> + Send + Sync, C: Clone + Send + Sync> CallbackContextWrapperExt<C> for T {
    fn with_context(self: T, context: C) -> ContextWrapper<T, C> {
         ContextWrapper::<T, C>::new(self, context)
    }
}

#[async_trait]
impl<T: CallbackApi<C> + Send + Sync, C: Clone + Send + Sync> CallbackApiNoContext<C> for ContextWrapper<T, C> {

    fn context(&self) -> &C {
        ContextWrapper::context(self)
    }

{{#apiInfo}}
  {{#apis}}
    {{#operations}}
      {{#operation}}
        {{#callbacks}}
          {{#urls}}
            {{#requests}}
              {{#summary}}
    /// {{{.}}}
              {{/summary}}
    async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}(
        &self,
{{#exts}}
  {{#x-callback-params}}
        callback_{{.}}: String,
  {{/x-callback-params}}
{{/exts}}
{{#allParams}}
        {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{{dataType}}}{{^required}}>{{/required}},
{{/allParams}}
        ) -> Result<{{{operationId}}}Response, ApiError>
    {
        let context = self.context().clone();
        self.api().{{#exts}}{{{x-operation-id}}}{{/exts}}(
{{#exts}}
  {{#x-callback-params}}
            callback_{{.}},
  {{/x-callback-params}}
{{/exts}}
{{#allParams}}
            {{{paramName}}},
{{/allParams}}
            &context).await
    }

            {{/requests}}
          {{/urls}}
        {{/callbacks}}
      {{/operation}}
    {{/operations}}
  {{/apis}}
{{/apiInfo}}
}

{{/hasCallbacks}}

#[cfg(feature = "client")]
pub mod client;

// Re-export Client as a top-level name
#[cfg(feature = "client")]
pub use client::Client;

#[cfg(feature = "server")]
pub mod server;

// Re-export router() as a top-level name
#[cfg(feature = "server")]
pub use self::server::Service;

{{#hasCallbacks}}
#[cfg(any(feature = "client", feature = "server"))]
{{/hasCallbacks}}
{{^hasCallbacks}}
#[cfg(feature = "server")]
{{/hasCallbacks}}
pub mod context;

pub mod models;

#[cfg(any(feature = "client", feature = "server"))]
pub(crate) mod header;
